import copy
import json
import requests
from patagent.utils.data_util import dataUtil
from patagent.constant import SWAGGER_URL
from langchain_core.tools import tool


class SwaggerParse():
    _data = dataUtil()

    api_data = {}
    base_path = ''
    api = {}
    api_uri_list = []  # 创建接口地址空列表
    api_method_list = []  # 创建请求方式空列表
    api_name_list = []  # 创建接口描述空列表
    api_params_path_list = []
    api_params_path_list_descs = []
    api_params_body_list = []
    api_params_body_list_descs = []
    # 定义响应相关内容
    api_response_key='200'
    api_response_body_list = []
    api_response_body_list_descs = []
    api_uri=""
    # 定义接口参数描述中各个类型的默认值
    api_params_ref_result_properties_type_default = {
        "int":0,"integer":0, "number":0,"float":0.0,"double":0.0,
        "null":None,"object":dict(),"set":set(),"string":"","array":[],
        "bool":False,"boolean":False,
    }

    def get_info_info(self):
        '''解析api数据'''
        def dispose_api_params_desc_result(api_params,api_params_ref_result,api_data):
            '''处理请求参数中的key，转为jsonpath提取数据并返回'''
            def replece_key(api_params_ref_json_path,api_data,split_symbol='.'):
                '''处理引用为标准的jsonpath，并替换原dict key'''
                if api_params_ref_json_path.startswith('$.'):
                    api_params_ref_json_path_split = api_params_ref_json_path.split(split_symbol)
                    if api_params_ref_json_path_split[1] in api_data.keys():
                        keys=list(api_data[api_params_ref_json_path_split[1]].keys())
                        if api_params_ref_json_path_split[2] in keys:
                            target_no_special_key=api_params_ref_json_path_split[2].replace("«", "").replace("»","").replace(',','')
                            if " " in api_params_ref_json_path_split[2]:
                                target_no_special_key=target_no_special_key.split(" ")[0]

                            ## 定义去除特殊字符后的目标key
                            if not api_data[api_params_ref_json_path_split[1]].\
                                    get(target_no_special_key):
                                api_data[api_params_ref_json_path_split[1]][target_no_special_key] = \
                                    api_data[api_params_ref_json_path_split[1]][api_params_ref_json_path_split[2]]
                                del api_data[api_params_ref_json_path_split[1]][api_params_ref_json_path_split[2]]

                return api_data

            api_params_ref_is_array=False #标识接口参数是否为array
            if not api_params:
                return "描述key为空",api_params_ref_result,api_params_ref_is_array
            '''解析请求参数为json数据的接口'''
            api_params_ref = api_params
            # params专用
            if api_params.get("schema"):
                if api_params.get("schema").get("$ref"):
                    api_params_ref=api_params['schema']['$ref']

            # response专用
            elif api_params.get("data"):
                if api_params.get("data").get("$ref"):
                    api_params_ref=api_params['data']['$ref']

            elif api_params.get("$ref"):
                api_params_ref = api_params['$ref']

            # '''解析请求参数格式为非json的数据，例如：array[object]'''
            if not str(api_params_ref).startswith('#'):
                # print("api_params_ref:",api_params_ref)
                api_params_ref_type = {}
                if api_params.get("schema"):
                    if api_params.get("schema").get("type"):
                        api_params_ref_type = api_params['schema']['type']

                elif api_params.get("data"):
                    if api_params.get("data").get("type"):
                        api_params_ref_type = api_params['data']['type']

                if api_params_ref_type:
                    if api_params_ref_type in self.api_params_ref_result_properties_type_default.keys():
                        api_params_ref = api_params['schema']['items']['$ref'] if api_params.get(
                            'schema') and api_params.get('schema').get('items') and \
                            api_params.get('schema').get('items').get('$ref') else api_params
                        if api_params_ref_type == 'array':
                            api_params_ref_is_array = True
                else:
                    api_params_ref_type = api_params['type'] if api_params.get('type') and api_params.get(
                        'items') else {}

                    if api_params_ref_type:
                        if api_params_ref_type in self.api_params_ref_result_properties_type_default.keys():
                            api_params_ref = api_params['items']['$ref'] if api_params.get(
                                'items') and api_params.get('items').get('$ref') else api_params
                            if api_params_ref_type == 'array':
                                api_params_ref_is_array = True


            api_params_ref_json_path = str(api_params_ref).replace('#', '$').replace('/', '.')
            if " " in api_params_ref_json_path:
                api_data=replece_key(api_params_ref_json_path=api_params_ref_json_path,api_data=api_data)
                api_params_ref_json_path_all = api_params_ref_json_path.split(' ')
                api_params_ref_json_path = api_params_ref_json_path_all[0]
            elif "«" in api_params_ref_json_path or "»" in api_params_ref_json_path:
                api_data=replece_key(api_params_ref_json_path=api_params_ref_json_path,api_data=api_data)
                api_params_ref_json_path=api_params_ref_json_path.replace("«","").replace("»","").replace(',','')

            if api_params_ref_json_path.startswith("$."):
                api_params_ref_result = self._data.json_path_parse_public(json_obj=api_data, json_path=api_params_ref_json_path)
            api_params_ref_result = api_params_ref_result[0] if api_params_ref_result and len(api_params_ref_result)==1 else api_params_ref_result
            return api_params_ref,api_params_ref_result,api_params_ref_is_array

        def api_params_desc_convert_to_params(api_params_ref_result:dict,api_data:dict):
            '''将接口示例对象转换为可用的请求参数'''
            def recursion_get_api_child_parms(properties_key, api_params_ref_result):
                '''递归解析子节点参数信息'''
                api_params_ref, api_params_ref_result, api_params_ref_is_array = dispose_api_params_desc_result(
                    api_params=api_params_ref_result_properties[i],
                    api_params_ref_result=api_params_ref_result, api_data=api_data)
                # api_params_ref没有#时，代表不再有json参数嵌套，不在调用
                if str(api_params_ref).startswith("#/"):
                    api_params = api_params_desc_convert_to_params(api_params_ref_result=api_params_ref_result,
                                                                   api_data=self.api_data)
                    properties_child_dict = {properties_key: api_params}
                    return api_params_ref_is_array,properties_child_dict
                return False,{}
            _api_params_ref_result_properties_dict = dict()
            if (not api_params_ref_result) or isinstance(api_params_ref_result,str) :
                return _api_params_ref_result_properties_dict

            api_params_ref_result_format=api_params_ref_result['type'] if api_params_ref_result.get('type') else api_params_ref_result
            if api_params_ref_result_format=='object':
                api_params_ref_result_properties=api_params_ref_result['properties'] if api_params_ref_result.get('properties') else {}
                for i in api_params_ref_result_properties:
                    # print("api_params_ref_result_properties[i]:",api_params_ref_result_properties[i])
                    if isinstance(api_params_ref_result_properties[i],dict) and \
                        (api_params_ref_result_properties[i].get('items')
                         and api_params_ref_result_properties[i].get('items').get("$ref") ) \
                        or api_params_ref_result_properties[i].get("$ref")\
                        or (api_params_ref_result_properties[i].get("schema") and api_params_ref_result_properties[i].get("schema").get('$ref')):
                        # print("开始递归处理")
                        api_params_ref_is_array,properties_child_dict=recursion_get_api_child_parms(properties_key=i,api_params_ref_result=api_params_ref_result)
                        if api_params_ref_is_array:
                            for cd in properties_child_dict:
                                if not isinstance(properties_child_dict[cd],(list,tuple,set)):
                                    properties_child_dict[cd]=[properties_child_dict[cd]]

                        _api_params_ref_result_properties_dict.update(properties_child_dict)
                    else:
                        api_params_ref_result_properties_type=api_params_ref_result_properties[i]['type'] if \
                            api_params_ref_result_properties[i].get('type') else 'string'
                        # 如果存在参数示例，则使用参数示例代替定义的默认值
                        api_params_ref_result_properties_example=api_params_ref_result_properties[i]['example'] if \
                            api_params_ref_result_properties[i].get('example') else None
                        if api_params_ref_result_properties_example:
                            if isinstance(api_params_ref_result_properties_example, str):
                                api_params_ref_result_properties_example = api_params_ref_result_properties_example.replace(
                                    '"', '').replace("'", '').replace(' ','')
                                if api_params_ref_result_properties_example.startswith('[') and api_params_ref_result_properties_example.endswith(']'):
                                    api_params_ref_result_properties_example=api_params_ref_result_properties_example[1:-1].split(',')
                                # print("api_params_ref_result_properties_example:",api_params_ref_result_properties_example)
                            _api_params_ref_result_properties_dict[i]=api_params_ref_result_properties_example
                        else:
                            _api_params_ref_result_properties_dict[i]=\
                            self.api_params_ref_result_properties_type_default[api_params_ref_result_properties_type]
                # print(_api_params_ref_result_properties_dict)
                return _api_params_ref_result_properties_dict

        def dispost_output_api_params(api_params,api_params_type,api_params_ref_result):
            '''api_params_type跟据输出最终需要的api_params'''
            if not api_params:
                return "描述key为空",[],{}
            __api_params=copy.deepcopy(api_params)
            if api_params_type!='response':
                api_params=[i for i in api_params if api_params_type in i.values()]
            if api_params_type in ('body','response'):
                if api_params:
                    if isinstance(api_params,list):
                        api_params=api_params[0]
                    else:
                        api_params=api_params
                else:
                    api_params={}
                '''处理body参数'''
                api_params_ref,api_params_ref_result,api_params_ref_is_array=dispose_api_params_desc_result(
                    api_params=api_params,api_params_ref_result=api_params_ref_result,api_data=self.api_data)
                # #将api参数转换为最终需要的格式
                api_params_out=api_params_desc_convert_to_params(api_params_ref_result=api_params_ref_result,api_data=self.api_data)
                if api_params_ref_is_array and ( not isinstance(api_params_out,(list,tuple))):
                    api_params_out=[api_params_out]
                return api_params_ref,api_params_ref_result,api_params_out
            elif api_params_type in ('path','query'):
                '''处理path参数'''
                api_params_ref="参数为path的请求没有描述key（不存在外部引用）"
                if not api_params:
                    if api_params_type=='path':
                        api_params_type='query'
                    elif api_params_type=='query':
                        api_params_type='path'
                    api_params = [i for i in __api_params if api_params_type in i.values()]
                api_params_ref_result=api_params
                api_params_out=dict()
                for api_param_dict in api_params:
                    params_type=api_param_dict['type'] if api_param_dict.get('type') else 'string'
                    params_filed=api_param_dict['name'] if api_param_dict.get('name') else None
                    if params_filed :
                        api_params_out[params_filed]=api_param_dict
                return api_params_ref,api_params_ref_result,api_params_out


        for path in self.api.keys():  # 循环取key
            values = self.api[path]  # 根据key获取值
            self.api_uri=path
            api_params_ref_result = "描述结果为空"  # 保存请求示例中的额外嵌套的信息
            api_response_ref_result = "响应结果为空"  # 保存请求示例中的额外嵌套的信息
            # if path=='/v1/collector/find-aggregate':
            for i in values.keys():
                self.api_uri_list.append(self.base_path + path)  # 将path写入接口地址列表中
                api_method = i  # 获取请求方式，文件中请求方式是key
                self.api_method_list.append(api_method)  # 将method写入请求方式列表中
                tags = values[api_method]['tags'][0]  # 获取接口分类
                # # 抓取参数与body
                api_params=values[api_method]['parameters'] if values[api_method].get('parameters') else {}
                api_params_ref_path,api_params_ref_result_path,api_params_path=dispost_output_api_params(
                    api_params=api_params,api_params_type='path',api_params_ref_result=api_params_ref_result)
                api_params_ref_body,api_params_ref_result_body,api_params_body=dispost_output_api_params(
                    api_params=api_params,api_params_type='body',api_params_ref_result=api_params_ref_result)
                self.api_params_path_list_descs.append(f"{api_params_ref_path}:->>{json.dumps(api_params_ref_result_path,ensure_ascii=False)}")
                self.api_params_path_list.append(json.dumps(api_params_path,ensure_ascii=False))
                self.api_params_body_list_descs.append(f"{api_params_ref_body}:->>{json.dumps(api_params_ref_result_body,ensure_ascii=False)}")
                self.api_params_body_list.append(json.dumps(api_params_body,ensure_ascii=False))
                # 抓取响应，Model 的嵌套太深容易超出最大递归深度
                # api_response=values[api_method]['responses'][self.api_response_key] if values[api_method].get('responses') and \
                #     values[api_method]['responses'].get(self.api_response_key) else {}
                # api_response_ref,api_response_ref_result,api_response=dispost_output_api_params(
                #     api_params=api_response,api_params_type='response',api_params_ref_result=api_response_ref_result)
                # if isinstance(api_response,list):
                #     api_response=api_response[0]
                # self.api_response_body_list_descs.append(f"{api_response_ref}:->>{json.dumps(api_response_ref_result,ensure_ascii=False)}")
                # self.api_response_body_list.append(json.dumps(api_response,ensure_ascii=False))

                # 拼接api_name
                summary = values[api_method]['summary']  # 获取接口描述
                self.api_name_list.append(tags + '_' + summary)

    def main(self, url=None):
        if url is None:
            url = SWAGGER_URL
        api_str = requests.get(url).text.replace("\n", '').replace('{\\\"topic\\\":\\\"离子通道优化的三维多孔界面结构\\\",\\\"description\\\":\\\"应用TRIZ<strong>第17条原理（维度转换）</strong>，设计具有三维网络结构的多孔界面层。采用<strong>定向冰模板法</strong>在隔膜/电极界面构建垂直于电极表面的定向微孔通道（孔径2-5μm，孔隙率40-45%）。这种结构可提供更大的离子传输截面积和更短的传输路径，使界面离子电导率提高至0.8-1.2 mS/cm（常规界面约0.3-0.5 mS/cm），界面阻抗降低约70%。实测显示，优化后电池能量密度可达270Wh/kg，倍率性能提升40%，且体积变化控制在±2%以内。\\\",\\\"contraction\\\":\\\"【核心矛盾】传统平面界面结构导致离子传输受限，界面阻抗大。\\\",\\\"innovation\\\":0,\\\"route_name\\\":\\\"界面阻抗过大\\\",\\\"route_id\\\":\\\"7e5d943129c0fdd9a0cd61f7bff24fe0\\\",\\\"node_id\\\":\\\"4f94d0ea31e2f17d1849ba489608f5ba\\\"}', '{"topic":"离子通道优化的三维多孔界面结构","description":"应用TRIZ<strong>第17条原理（维度转换）</strong>，设计具有三维网络结构的多孔界面层。采用<strong>定向冰模板法</strong>在隔膜/电极界面构建垂直于电极表面的定向微孔通道（孔径2-5μm，孔隙率40-45%）。这种结构可提供更大的离子传输截面积和更短的传输路径，使界面离子电导率提高至0.8-1.2 mS/cm（常规界面约0.3-0.5 mS/cm），界面阻抗降低约70%。实测显示，优化后电池能量密度可达270Wh/kg，倍率性能提升40%，且体积变化控制在±2%以内。","contraction":"【核心矛盾】传统平面界面结构导致离子传输受限，界面阻抗大。","innovation":0,"route_name":"界面阻抗过大","route_id":"7e5d943129c0fdd9a0cd61f7bff24fe0","node_id":"4f94d0ea31e2f17d1849ba489608f5ba"}').replace("'head_player_analysis'", '"head_player_analysis"').replace("'key_patent_interpretation'", '"key_patent_interpretation"')
        self.api_data = json.loads(api_str)
        self.base_path = 'https://' + self.api_data['host'] + self.api_data['basePath']
        self.api = self.api_data['paths']  # 取swagger文件内容中的path，文件中path是键名
        self.get_info_info()


@tool
def swagger_parse(url: str) -> list:
    """parse swagger json with a swagger url"""
    sp = SwaggerParse()
    sp.main(url)
    return sp.api_name_list


if __name__=="__main__":
    sp = SwaggerParse()
    sp.main()
    print(sp.api_name_list)